package com.apobates.jforum.grief.schema2doc.jdbc.dialect;

import com.apobates.jforum.grief.schema2doc.core.SchemaTableStrategy;
import com.apobates.jforum.grief.schema2doc.core.entity.Column;
import com.apobates.jforum.grief.schema2doc.core.entity.Nullable;
import com.apobates.jforum.grief.schema2doc.core.entity.PrimayKey;
import com.apobates.jforum.grief.schema2doc.core.entity.Table;
import com.apobates.jforum.grief.schema2doc.jdbc.schema.AbstractQueryExecutor;
import com.apobates.jforum.grief.schema2doc.core.schema.SchemaDialect;
import com.apobates.jforum.grief.schema2doc.core.strategy.SchemaTableRegMatchStrategy;
import org.jooq.DSLContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import java.util.Optional;
import java.util.stream.Stream;
/**
 * SQLite的结果集供应商
 */
public class JooqQuerySQLiteExecutor extends AbstractQueryExecutor {
    private final static Logger logger = LoggerFactory.getLogger(JooqQuerySQLiteExecutor.class);

    public JooqQuerySQLiteExecutor(DataSource dataSource, SchemaDialect dialect) {
        super(dataSource, dialect);
    }

    @Override
    protected Stream<Table> getTables(DSLContext context, Optional<String> dbName, Optional<String> schema, SchemaTableStrategy tableStrategy) throws IllegalArgumentException {
        if(tableStrategy instanceof SchemaTableRegMatchStrategy){
            logger.warn("SQLite不支持此策略. 原生不支持正则表达式函数");
        }
        // https://www.sqlitetutorial.net/sqlite-describe-table/
        String sql = "SELECT name, rootpage FROM sqlite_schema WHERE type = 'table'";
        if(tableStrategy.sql(SchemaDialect.SQLite).isPresent()){
            sql+= " AND " + tableStrategy.sql(SchemaDialect.SQLite).get().replaceAll(SchemaTableStrategy.placeholder, "name");
        }
        logger.debug("[TABLE-SQLite]execute sql statement::"+sql);
        return context.fetch(sql).stream().map(record -> {
            // String dbName, String tableName, String remarks
            return Table.noSchema(
                    record.get("rootpage", int.class),
                    dbName.get(),
                    record.get("name", String.class),
                    "remarks");
        }).filter(table->tableStrategy.filter().test(table.getTableName()));
    }

    @Override
    protected Stream<Column> getColumns(DSLContext context, Table table) {
        // https://sqldocs.org/sqlite/sqlite-show-table-columns/
        // https://database.guide/5-ways-to-check-a-columns-data-type-in-sqlite/
        // SELECT name,type,`notnull`, dflt_value,pk FROM pragma_table_info('sys_items');
        String sql = "SELECT name, type,`notnull`, dflt_value, pk FROM pragma_table_info('%s')";
        sql = String.format(sql, table.getTableName());
        logger.debug("[COLUMN-SQLite]execute sql statement::"+sql+", Table Arg::"+table.getTableName());
        return context.fetch(sql).stream().map(record -> {
            // Basic:: String columnName, String typeName, String columnSize, Nullable nullable, String remarks
            String columnName = record.get("name", String.class);
            return Column.basic(
                            columnName,
                            record.get("type", String.class),
                            "0",
                            Nullable.of(record.get("notnull", String.class).equals("0")?1:2), // 1(NOT NULL/E:NO)/0(NULL/E:YES)
                            "REMARKS")
                    .toFull("0",
                            PrimayKey.of(record.get("pk", String.class).equals("1")?1:2),
                            record.get("dflt_value", String.class)); // String decimalDigits, PrimayKey pk, String columnDef
        });
    }
}
